package com.vcc.service.impl;


import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.CardType;
import com.vcc.data.entity.UserCardWallet;
import com.vcc.data.mapper.UserCardWalletMapper;
import com.vcc.service.boss.request.userCard.BatchUserCardWalletDto;
import com.vcc.service.boss.request.userCard.UserCardWalletDto;
import com.vcc.service.service.UserCardWalletService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import static com.mybatisflex.core.query.QueryMethods.select;
import static com.vcc.data.entity.table.UserCardWalletTableDef.USER_CARD_WALLET;
import static com.vcc.data.entity.table.UserTableDef.USER;

@Service
public class UserCardWalletServiceImpl extends ServiceImpl<UserCardWalletMapper, UserCardWallet> implements UserCardWalletService {


    @Override
    public UserCardWallet getById(Long id) {
        return queryChain().eq(UserCardWallet::getId, id).oneOpt().orElseThrow(() -> new NotFoundException("没有当前卡钱包"));
    }

    @Override
    public List<UserCardWallet> listByUserId(Long userId) {
        return queryChain().eq(UserCardWallet::getUserId, userId).list();
    }

    @Override
    public List<UserCardWallet> listByUserId(Long userId, Collection<Long> cardIds) {
        if (cardIds == null || cardIds.isEmpty()) {
            return listByUserId(userId);
        }
        return queryChain()
                .eq(UserCardWallet::getUserId, userId)
                .in(UserCardWallet::getCardId, cardIds)
                .list();
    }

    @Override
    public List<UserCardWallet> listByUserIds(Collection<Long> userIds) {
        return queryChain().in(UserCardWallet::getUserId, userIds).list();
    }

    @Override
    public UserCardWallet findByUserIdAndCardId(Long userId, Long cardId) {
        return queryChain()
                .eq(UserCardWallet::getUserId, userId)
                .eq(UserCardWallet::getCardId, cardId)
                .oneOpt()
                .orElseThrow(() -> new NotFoundException("当前用户并未关联此卡种"));
    }


    @Override
    public Boolean updateInfo(UserCardWalletDto userCardWalletDto) {
        UserCardWallet userCardWallet = getById(userCardWalletDto.getId());
        UpdateChain<UserCardWallet> updateChain = updateChain();
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getVerifyOpenCardStatus()) && !userCardWallet.getVerifyOpenCardStatus().equals(userCardWalletDto.getVerifyOpenCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyOpenCardStatus, userCardWalletDto.getVerifyOpenCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getVerifyRechargeCardStatus()) && !userCardWallet.getVerifyRechargeCardStatus().equals(userCardWalletDto.getVerifyRechargeCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyRechargeCardStatus, userCardWalletDto.getVerifyRechargeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getVerifyOutCardStatus()) && !userCardWallet.getVerifyOutCardStatus().equals(userCardWalletDto.getVerifyOutCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyOutCardStatus, userCardWalletDto.getVerifyOutCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getVerifyCloseCardStatus()) && !userCardWallet.getVerifyOutCardStatus().equals(userCardWalletDto.getVerifyCloseCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyCloseCardStatus, userCardWalletDto.getVerifyCloseCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getVerifyFreezeUnFreezeCardStatus()) && !userCardWallet.getVerifyFreezeUnFreezeCardStatus().equals(userCardWalletDto.getVerifyFreezeUnFreezeCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyFreezeUnFreezeCardStatus, userCardWalletDto.getVerifyFreezeUnFreezeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getAmount()) && !Objects.equals(userCardWallet.getAmount().compareTo(userCardWalletDto.getAmount()), 0)) {
            updateChain.set(UserCardWallet::getAmount, userCardWalletDto.getAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getExchangeRate()) && !Objects.equals(userCardWallet.getExchangeRate().compareTo(userCardWalletDto.getExchangeRate()), 0)) {
            updateChain.set(UserCardWallet::getExchangeRate, userCardWalletDto.getExchangeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getOpenCardOnLineCount()) && !userCardWallet.getOpenCardOnLineCount().equals(userCardWalletDto.getOpenCardOnLineCount())) {
            updateChain.set(UserCardWallet::getOpenCardOnLineCount, userCardWalletDto.getOpenCardOnLineCount());
        }

        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getMinAuthFee()) && !userCardWallet.getMinAuthFee().equals(userCardWalletDto.getMinAuthFee())) {
            updateChain.set(UserCardWallet::getMinAuthFee, userCardWalletDto.getMinAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getMinAuthFeeRate()) && !userCardWallet.getMinAuthFeeRate().equals(userCardWalletDto.getMinAuthFeeRate())) {
            updateChain.set(UserCardWallet::getMinAuthFeeRate, userCardWalletDto.getMinAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getAuthFee()) && !userCardWallet.getAuthFee().equals(userCardWalletDto.getAuthFee())) {
            updateChain.set(UserCardWallet::getAuthFee, userCardWalletDto.getAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getAuthFeeRate()) && !userCardWallet.getAuthFeeRate().equals(userCardWalletDto.getAuthFeeRate())) {
            updateChain.set(UserCardWallet::getAuthFeeRate, userCardWalletDto.getAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getFailFee()) && !userCardWallet.getFailFee().equals(userCardWalletDto.getFailFee())) {
            updateChain.set(UserCardWallet::getFailFee, userCardWalletDto.getFailFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getFailFeeRate()) && !userCardWallet.getFailFeeRate().equals(userCardWalletDto.getFailFeeRate())) {
            updateChain.set(UserCardWallet::getFailFeeRate, userCardWalletDto.getFailFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getRefundFee()) && !userCardWallet.getRefundFee().equals(userCardWalletDto.getRefundFee())) {
            updateChain.set(UserCardWallet::getRefundFee, userCardWalletDto.getRefundFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getRefundFeeRate()) && !userCardWallet.getRefundFeeRate().equals(userCardWalletDto.getRefundFeeRate())) {
            updateChain.set(UserCardWallet::getRefundFeeRate, userCardWalletDto.getRefundFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getReversalFee()) && !userCardWallet.getReversalFee().equals(userCardWalletDto.getReversalFee())) {
            updateChain.set(UserCardWallet::getReversalFee, userCardWalletDto.getReversalFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getReversalFeeRate()) && !userCardWallet.getReversalFeeRate().equals(userCardWalletDto.getReversalFeeRate())) {
            updateChain.set(UserCardWallet::getReversalFeeRate, userCardWalletDto.getReversalFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getCrossBorderFee()) && !userCardWallet.getCrossBorderFee().equals(userCardWalletDto.getCrossBorderFee())) {
            updateChain.set(UserCardWallet::getCrossBorderFee, userCardWalletDto.getCrossBorderFee());
        }
        if (RegexUtil.checkObjectIsNotNull(userCardWalletDto.getCrossBorderFeeRate()) && !userCardWallet.getCrossBorderFeeRate().equals(userCardWalletDto.getCrossBorderFeeRate())) {
            updateChain.set(UserCardWallet::getCrossBorderFeeRate, userCardWalletDto.getCrossBorderFeeRate());
        }
        updateChain.eq(UserCardWallet::getId, userCardWallet.getId());
        //如果被操作者是主站户，则子账户同步
        boolean update = updateChain.update();
        if (update && userCardWallet.getUserId() != null && userCardWallet.getUserId() > 0) {
            updateSubAccountRate(userCardWalletDto, userCardWallet.getUserId());
        }
        return update;
    }

    private void updateSubAccountRate(UserCardWalletDto userCardWalletDto, Long userId) {
        UpdateChain<UserCardWallet> updateChain = updateChain()
                .set(UserCardWallet::getVerifyOpenCardStatus, userCardWalletDto.getVerifyOpenCardStatus(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getVerifyRechargeCardStatus, userCardWalletDto.getVerifyRechargeCardStatus(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getVerifyOutCardStatus, userCardWalletDto.getVerifyOutCardStatus(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getVerifyCloseCardStatus, userCardWalletDto.getVerifyCloseCardStatus(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getVerifyFreezeUnFreezeCardStatus, userCardWalletDto.getVerifyFreezeUnFreezeCardStatus(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getMinAuthFee, userCardWalletDto.getMinAuthFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getMinAuthFeeRate, userCardWalletDto.getMinAuthFeeRate(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getAuthFee, userCardWalletDto.getAuthFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getAuthFeeRate, userCardWalletDto.getAuthFeeRate(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getFailFee, userCardWalletDto.getFailFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getFailFeeRate, userCardWalletDto.getFailFeeRate(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getRefundFee, userCardWalletDto.getRefundFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getRefundFeeRate, userCardWalletDto.getRefundFeeRate(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getReversalFee, userCardWalletDto.getReversalFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getReversalFeeRate, userCardWalletDto.getReversalFeeRate(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getCrossBorderFee, userCardWalletDto.getCrossBorderFee(), RegexUtil::checkObjectIsNotNull)
                .set(UserCardWallet::getCrossBorderFeeRate, userCardWalletDto.getCrossBorderFeeRate(), RegexUtil::checkObjectIsNotNull);
        //查询当前用户下的子账户
        updateChain.where(USER_CARD_WALLET.USER_ID.in(select(USER.ID).from(USER).where(USER.PARENT_ID.eq(userId))))
                .update();
    }

    @Override
    public Boolean batchUpdateInfo(BatchUserCardWalletDto batchUserCardWalletDto) {
        UpdateChain<UserCardWallet> updateChain = updateChain();
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getVerifyOpenCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyOpenCardStatus, batchUserCardWalletDto.getVerifyOpenCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getVerifyRechargeCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyRechargeCardStatus, batchUserCardWalletDto.getVerifyRechargeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getVerifyOutCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyOutCardStatus, batchUserCardWalletDto.getVerifyOutCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getVerifyCloseCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyCloseCardStatus, batchUserCardWalletDto.getVerifyCloseCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getVerifyFreezeUnFreezeCardStatus())) {
            updateChain.set(UserCardWallet::getVerifyFreezeUnFreezeCardStatus, batchUserCardWalletDto.getVerifyFreezeUnFreezeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getAmount()) && batchUserCardWalletDto.getAmount().compareTo(BigDecimal.valueOf(-1)) > -1) {
            updateChain.set(UserCardWallet::getAmount, batchUserCardWalletDto.getAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getExchangeRate()) && batchUserCardWalletDto.getExchangeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getExchangeRate, batchUserCardWalletDto.getExchangeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getOpenCardOnLineCount()) && batchUserCardWalletDto.getOpenCardOnLineCount() > -1) {
            updateChain.set(UserCardWallet::getOpenCardOnLineCount, batchUserCardWalletDto.getOpenCardOnLineCount());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getMinAuthFee()) && batchUserCardWalletDto.getMinAuthFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getMinAuthFee, batchUserCardWalletDto.getMinAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getMinAuthFeeRate()) && batchUserCardWalletDto.getMinAuthFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getMinAuthFeeRate, batchUserCardWalletDto.getMinAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getAuthFee()) && batchUserCardWalletDto.getAuthFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getAuthFee, batchUserCardWalletDto.getAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getAuthFeeRate()) && batchUserCardWalletDto.getAuthFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getAuthFeeRate, batchUserCardWalletDto.getAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getFailFee()) && batchUserCardWalletDto.getFailFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getFailFee, batchUserCardWalletDto.getFailFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getFailFeeRate()) && batchUserCardWalletDto.getFailFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getFailFeeRate, batchUserCardWalletDto.getFailFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getRefundFee()) && batchUserCardWalletDto.getRefundFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getRefundFee, batchUserCardWalletDto.getRefundFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getRefundFeeRate()) && batchUserCardWalletDto.getRefundFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getRefundFeeRate, batchUserCardWalletDto.getRefundFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getReversalFee()) && batchUserCardWalletDto.getReversalFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getReversalFee, batchUserCardWalletDto.getReversalFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getReversalFeeRate()) && batchUserCardWalletDto.getReversalFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getReversalFeeRate, batchUserCardWalletDto.getReversalFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getCrossBorderFee()) && batchUserCardWalletDto.getCrossBorderFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getCrossBorderFee, batchUserCardWalletDto.getCrossBorderFee());
        }
        if (RegexUtil.checkObjectIsNotNull(batchUserCardWalletDto.getCrossBorderFeeRate()) && batchUserCardWalletDto.getCrossBorderFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(UserCardWallet::getCrossBorderFeeRate, batchUserCardWalletDto.getCrossBorderFeeRate());
        }
        updateChain.in(UserCardWallet::getUserId, batchUserCardWalletDto.getUserIds());
        updateChain.in(UserCardWallet::getCardId, batchUserCardWalletDto.getCardIds());
        updateChain.update();

        return true;
    }

    @Override
    public Boolean init(List<CardType> cardIds, Long userId) {
        List<UserCardWallet> list = new ArrayList<>();
        cardIds.forEach(it -> {
            list.add(new UserCardWallet(
                    userId,
                    it.getId(),
                    BigDecimal.valueOf(-1),
                    BigDecimal.valueOf(0),
                    0,
                    0,
                    0,
                    0,
                    0,
                    20,
                    it
            ));
        });
        saveBatch(list);
        return true;
    }

    @Override
    public Boolean init(List<CardType> cardIds, Long userId, Long parentId) {
        List<UserCardWallet> list = new ArrayList<>();
        List<UserCardWallet> parentUserWallets = listByUserId(parentId);
        cardIds.forEach(it -> {
            UserCardWallet userCardWallet = new UserCardWallet(
                    userId,
                    it.getId(),
                    BigDecimal.valueOf(-1),
                    BigDecimal.valueOf(0),
                    0,
                    0,
                    0,
                    0,
                    0,
                    20,
                    it
            );
            UserCardWallet parentUserWallet = parentUserWallets.stream().filter(parent -> parent.getCardId().equals(it.getId())).findFirst().orElse(null);
            userCardWallet.setAmount(parentUserWallet != null ? parentUserWallet.getAmount() : it.getAmount());
            userCardWallet.setExchangeRate(parentUserWallet != null ? parentUserWallet.getExchangeRate() : BigDecimal.ZERO);
            userCardWallet.setAuthFee(parentUserWallet != null ? parentUserWallet.getAuthFee() : it.getAuthFee());
            userCardWallet.setAuthFeeRate(parentUserWallet != null ? parentUserWallet.getAuthFeeRate() : it.getAuthFeeRate());
            userCardWallet.setMinAuthFee(parentUserWallet != null ? parentUserWallet.getMinAuthFee() : it.getMinAuthFee());
            userCardWallet.setMinAuthFeeRate(parentUserWallet != null ? parentUserWallet.getMinAuthFeeRate() : it.getMinAuthFeeRate());
            userCardWallet.setFailFee(parentUserWallet != null ? parentUserWallet.getFailFee() : it.getFailFee());
            userCardWallet.setFailFeeRate(parentUserWallet != null ? parentUserWallet.getFailFeeRate() : it.getFailFeeRate());
            userCardWallet.setRefundFee(parentUserWallet != null ? parentUserWallet.getRefundFee() : it.getRefundFee());
            userCardWallet.setRefundFeeRate(parentUserWallet != null ? parentUserWallet.getRefundFeeRate() : it.getRefundFeeRate());
            userCardWallet.setReversalFee(parentUserWallet != null ? parentUserWallet.getReversalFee() : it.getReversalFee());
            userCardWallet.setReversalFeeRate(parentUserWallet != null ? parentUserWallet.getReversalFeeRate() : it.getReversalFeeRate());
            userCardWallet.setCrossBorderFee(parentUserWallet != null ? parentUserWallet.getCrossBorderFee() : it.getCrossBorderFee());
            userCardWallet.setCrossBorderFeeRate(parentUserWallet != null ? parentUserWallet.getCrossBorderFeeRate() : it.getCrossBorderFeeRate());
            list.add(userCardWallet);
        });
        saveBatch(list);
        return true;
    }

    @Override
    public Boolean addCardInit(CardType card, List<Long> userIds) {
        List<UserCardWallet> list = new ArrayList<>();
        userIds.forEach(it -> {
            list.add(
                    new UserCardWallet(
                            it,
                            card.getId(),
                            BigDecimal.valueOf(-1),
                            BigDecimal.valueOf(0),
                            0,
                            0,
                            0,
                            0,
                            0,
                            20,
                            card
                    )
            );
        });
        saveBatch(list);
        return true;
    }
}
